#include "dominion.h"
#include "testutils.h"
#include <stdio.h>
#include <stdlib.h>

// This unit test was added after it was found via random testing that the
// minion card was introducing invalid cards with the value of -1 into 
// players' decks. All combinations of card positions are tested. 

void testMinionEffect ( int args[MAX_PLAYARGS], int cardtypes[MAX_PLAYARGS],
                        carddesc_t desc, struct gameState *g,
                        expectedState_t *expected )
{
    pass_printf ("%s: TEST playing %s\n", __func__, desc[0]);
    
    int flags = args[4];
    bool otherPlayersNeedShuffle = (flags & 1) != 0;
    bool thisPlayerNeedsShuffle = (flags & 2) != 0;
    bool attack = (flags & 4) != 0;
    
    if (otherPlayersNeedShuffle)
        pass_printf ("\tOther players will need shuffle.\n");
    else
        pass_printf ("\tOther players won't need shuffle.\n");
    
    if (thisPlayerNeedsShuffle)
        pass_printf ("\tCurrent player will need shuffle.\n");
    else
        pass_printf ("\tCurrent player won't need shuffle.\n");
    
    int player = g->whoseTurn;
    
    if (otherPlayersNeedShuffle)
    {
        for (int i = 0; i < g->numPlayers; i++)
        {
            if (i == player)
                continue;
            
            while (g->deckCount[i])
                g->discard[i][g->discardCount[i]++] = g->deck[i][--g->deckCount[i]];
        }
    }
    
    if (thisPlayerNeedsShuffle)
    {
        while (g->deckCount[player])
            g->discard[player][g->discardCount[player]++] = g->deck[player][--g->deckCount[player]];
    }
    
    int choice1 = 0, choice2 = 0;
    int expectedCoins;
    
    if (attack)
    {
        pass_printf ("\tAttacking\n");
        choice2 = 1;
        
        for (int i = 0; i < 6; i++)
        {
            if (i == args[0])
                continue; // testPlayCard already handles this one
            expected->playedCount[g->hand[player][i]]++;
            expected->count[g->hand[player][i]]--;
        }
        
        if (!thisPlayerNeedsShuffle)
        {
            // We can only predict the number of coins we will have in the new
            // hand if the deck isn't going to be shuffled, otherwise it's
            // random.
            expectedCoins = 0;
            for (int i = 0; i < 4; i++)
            {
                if (g->deck[player][g->deckCount[player]-1-i] == copper)
                    expectedCoins++;
            }
        }
    }
    else
    {
        pass_printf ("\t+2 coins\n");
        choice1 = 1;
        expectedCoins = g->coins + 2;
    }
    
    testPlayCard (args[0], choice1, choice2, args[3], g, expected, false);
    
    if (!thisPlayerNeedsShuffle || !attack)
    {
        // We can only predict the number of coins we will have in the new
        // hand if the deck isn't going to be shuffled, otherwise it's random.
        assert_equal (g->coins, expectedCoins, "verifying number of coins");
    }
    
    if (attack)
    {
        for (int i = 0; i < g->numPlayers; i++)
        {
            int expectedMinionCount = i == player;
            int expectedDeckSize, expectedDiscardSize;
            
            assert_equal (  g->handCount[i], 4,
                            "verifying player %d's hand size", i );
            
            if (i == 0)
            {
                testEndTurn (g, expected);
            }
            else
            {
                // TODO: use testEndTurn for all players
                endTurn (g);
            }
            
            // TODO: think about what these numbers should be
#if 0
            assert_equal (  g->deckCount[i], expectedDeckSize,
                            "verifying player %d's deck pile size", i );
            assert_equal (  g->discardCount[i], expectedDiscardSize,
                            "verifying player %d's discard pile size", i );
#endif
        }
    }
    else
    {
        testEndTurn (g, expected);
    }
    
    for (int i = 0; i < g->numPlayers; i++)
    {
        int expectedMinionCount = i == player;
        int expectedCardCount = expectedMinionCount + 7 + 3;
        int actualCardCount = g->handCount[i] + g->deckCount[i] + g->discardCount[i];
        assert_equal (  actualCardCount, expectedCardCount,
                        "verifying player %d's total number of cards", i );
        assert_equal (  fullDeckCount (i, copper, g), 7,
                        "verifying player %d's number of copper cards", i );
        assert_equal (  fullDeckCount (i, estate, g), 3,
                        "verifying player %d's number of estate cards", i );
        assert_equal (  fullDeckCount (i, -1, g), 0,
                        "verifying player %d has no -1 cards", i );
    }
}

int main (int argc, char *argv[])
{
    parse_args (argc, argv);
    
    static playargs_t playargs =
    {
        {arg_handcard,  minion, minion},
        {arg_num,       0, 0},
        {arg_num,       0, 0},
        {arg_num,       0, 0},
        {arg_num,       0, 7} // 3 boolean flags to test combinations of
    };
    
    run_cardtest (playargs, testMinionEffect);
}
